package cn.iocoder.yudao.module.trade.service.order;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
import cn.iocoder.yudao.module.pay.api.order.PayOrderApi;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.TradeOrderCreateReqVO;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderOperateTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
import cn.iocoder.yudao.module.trade.framework.order.core.annotations.TradeOrderLog;
import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
import cn.iocoder.yudao.module.trade.service.cart.CartService;
import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
import cn.iocoder.yudao.module.trade.service.price.bo.TradeOrderRespBO;
import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getTerminal;

@Service
public class TradeOrderServiceImpl implements TradeOrderService {
    @Resource
    private ProductSkuApi productSkuApi;
    @Resource
    private ProductSpuApi productSpuApi;
    @Resource
    private TradeNoRedisDAO tradeNoRedisDAO;
    @Resource
    private MemberAddressApi addressApi;
    @Resource
    private List<TradeOrderHandler> tradeOrderHandlers;
    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private TradeOrderItemMapper tradeOrderItemMapper;
    @Resource
    private CartService cartService;
    @Resource
    private TradeOrderProperties tradeOrderProperties;
    @Resource
    private PayOrderApi payOrderApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MEMBER_CREATE)
    public List<TradeOrderDO> createOrder(Long userId, TradeOrderCreateReqVO createReqVO) {
        List<TradeOrderDO> orderIds = new ArrayList<>();

        // 遍历每组商品项，为每个商品创建一个订单
        for (TradeOrderCreateReqVO.Item item : createReqVO.getItems()) {
            // 1. 计算单个商品项的价格
            TradeOrderRespBO calculateRespBO = calculatePriceForSingleItem(userId, item);
            calculateRespBO.setSkuId(item.getSkuId());
            // 2. 构建订单和订单项
            TradeOrderDO order = buildSingleTradeOrder(userId, item, calculateRespBO);
            TradeOrderItemDO orderItems = buildTradeOrderItemsForSingleOrder(order, calculateRespBO);
            // 创建一个 TradeOrderItemDO 类型的 ArrayList
            List<TradeOrderItemDO> itemsList = new ArrayList<>();
            itemsList.add(orderItems);
            // 3. 调用订单创建前的处理器
            executeBeforeOrderCreateHandlers(order, itemsList);

            // 4. 保存订单数据
            saveOrderData(createReqVO, order, itemsList, item);

            // 5. 调用订单创建后的处理器
            executeAfterOrderCreateHandlers(order, itemsList, item);

            // 将订单ID添加到列表中
            orderIds.add(order);
        }

        return orderIds;
    }

    @Override
    public Long selectCountByIdAndStatus(Long id, Integer status) {
        Long counts = tradeOrderMapper.selectCountByIdAndStatus(id, status);
        return counts;
    }


    private TradeOrderRespBO calculatePriceForSingleItem(Long userId, TradeOrderCreateReqVO.Item item) {
        // 计算单个商品项的价格（此处提供实现）
        // 假设 calculatePrice0 是一个通用价格计算方法，可以为单个商品项进行价格计算
        return calculatePrice0(userId, item);
    }

    private TradeOrderRespBO calculatePrice0(Long userId, TradeOrderCreateReqVO.Item item) {
        // 1.1 获得商品 SKU 数组
        ProductSkuRespDTO sku = checkSku(item);
        // 1.2 获得商品 SPU 数组
        ProductSpuRespDTO spu = checkSpu(sku);
        TradeOrderRespBO calculateRespBO = TradePriceCalculatorHelper
                .buildOrderCalculateResp(spu, sku, item);
        calculateRespBO.setPayPrice(calculateRespBO.getPrice() * calculateRespBO.getCount() + calculateRespBO.getDeliveryPrice());
        return calculateRespBO;

    }

    private ProductSpuRespDTO checkSpu(ProductSkuRespDTO sku) {
        return productSpuApi.getSpu(sku.getSpuId());
    }

    private ProductSkuRespDTO checkSku(TradeOrderCreateReqVO.Item item) {
        return productSkuApi.getSku(item.getSkuId());
    }


    private TradeOrderDO buildSingleTradeOrder(Long userId, TradeOrderCreateReqVO.Item item, TradeOrderRespBO calculateRespBO) {
        // 实现创建单个订单的方法
        TradeOrderDO order = TradeOrderConvert.INSTANCE.convertOrder(userId, item, calculateRespBO);
        order.setType(0);
        order.setMerchantId(calculateRespBO.getMerchantId());
        order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX));
        order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
        order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
        order.setProductCount(calculateRespBO.getCount());
        order.setUserIp(getClientIP()).setTerminal(getTerminal());
        // 支付 + 退款信息
        order.setAdjustPrice(0).setPayStatus(false);
        order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
        order.setDeliveryType(item.getDeliveryType());

        if (Objects.equals(item.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
            // 快递配送
            MemberAddressRespDTO address = addressApi.getAddress(item.getAddressId(), userId);
            Assert.notNull(address, "地址({}) 不能为空", item.getAddressId());
            order.setReceiverName(address.getName())
                    .setReceiverMobile(address.getMobile())
                    .setReceiverAreaId(address.getAreaId())
                    .setReceiverDetailAddress(address.getDetailAddress());
        } else if (Objects.equals(item.getDeliveryType(), DeliveryTypeEnum.PICK_UP.getType())) {
            // 自提
            order.setReceiverName(item.getReceiverName())
                    .setReceiverMobile(item.getReceiverMobile());
            order.setPickUpVerifyCode(RandomUtil.randomNumbers(8));
        }

        order.setUserId(userId);
        order.setTotalPrice(calculateRespBO.getPayPrice());
        return order;
    }

    private TradeOrderItemDO buildTradeOrderItemsForSingleOrder(TradeOrderDO order, TradeOrderRespBO calculateRespBO) {
        return TradeOrderConvert.INSTANCE.convertItem(order, calculateRespBO);
    }

    private void executeBeforeOrderCreateHandlers(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
        // 执行所有订单创建前的处理器
        if (tradeOrderHandlers != null) {
            tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(order, orderItems));
        }
    }

    private void saveOrderData(TradeOrderCreateReqVO createReqVO, TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradeOrderCreateReqVO.Item item) {

        // 保存订单和订单项
        tradeOrderMapper.insert(order);
        orderItems.forEach(orderItem -> orderItem.setOrderId(order.getId()));
        tradeOrderItemMapper.insertBatch(orderItems);
    }

    private void executeAfterOrderCreateHandlers(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradeOrderCreateReqVO.Item item) {
        // 执行所有订单创建后的处理器
        afterCreateTradeOrder(order, orderItems, item);
    }

    private void afterCreateTradeOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradeOrderCreateReqVO.Item item) {
        // 1. 执行订单创建后置处理器
        tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(order, orderItems));

        // 2. 删除购物车商品
        Long cartId = item.getCartId();
        if (cartId != null) {
            cartService.deleteCartById(order.getUserId(), cartId);
        }

        // 3. 生成预支付
        createPayOrder(order, orderItems);

        // 4. 插入订单日志
        TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus());

    }


    private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems) {
        // 创建支付单，用于后续的支付
        PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert(
                order, orderItems, tradeOrderProperties);
        Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO);

        // 更新到交易单上
        tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setPayOrderId(payOrderId));
        order.setPayOrderId(payOrderId);
    }


}


